package com.one.judge.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.one.api.domain.UserExeResult;
import com.one.api.domain.dto.JudgeSubmitDTO;
import com.one.api.domain.vo.UserQuestionResultVO;
import com.one.common.core.constants.Constants;
import com.one.common.core.constants.JudgeConstants;
import com.one.common.core.enums.CodeRunStatus;
import com.one.judge.domain.SandBoxExecuteResult;
import com.one.judge.domain.UserSubmit;
import com.one.judge.mapper.UserSubmitMapper;
import com.one.judge.service.IJudgeSubmitService;
import com.one.judge.service.ISandboxPoolService;
import com.one.judge.service.ISandboxService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;

@Service
@Slf4j
public class JudgeSubmitServiceImpl implements IJudgeSubmitService {

    @Autowired
    private UserSubmitMapper userSubmitMapper;

    @Autowired
    private ISandboxPoolService iSandboxPoolService;

    @Autowired
    private ISandboxService iSandboxService;

    @Override
    public UserQuestionResultVO doJudgeJavaCode(JudgeSubmitDTO judgeSubmitDTO) {
        //判题逻辑
        UserQuestionResultVO userQuestionResultVO = new UserQuestionResultVO();
        //javac java执行代码   容器池版本
        SandBoxExecuteResult sandBoxExecuteResult = iSandboxPoolService
                .exeJavaCode(judgeSubmitDTO.getUserId(),judgeSubmitDTO.getUserCode(),judgeSubmitDTO.getInputList());
//        SandBoxExecuteResult sandBoxExecuteResult = iSandboxService
//                .exeJavaCode(judgeSubmitDTO.getUserId(), judgeSubmitDTO.getUserCode(), judgeSubmitDTO.getInputList());
        //拿到结果进行比对
        if(sandBoxExecuteResult != null && CodeRunStatus.SUCCEED.equals(sandBoxExecuteResult.getRunStatus())){
            userQuestionResultVO =  doJudge(judgeSubmitDTO, userQuestionResultVO, sandBoxExecuteResult);
        }else{
            //执行失败
            userQuestionResultVO.setPass(Constants.FALSE);
            if (sandBoxExecuteResult != null) {
                userQuestionResultVO.setExeMessage(sandBoxExecuteResult.getExeMessage());
            } else {
                userQuestionResultVO.setExeMessage(CodeRunStatus.UNKNOWN_FAILED.getMsg());
            }
            userQuestionResultVO.setScore(JudgeConstants.ERROR_SCORE);
        }
        saveUserSubmit(judgeSubmitDTO,userQuestionResultVO);
        return userQuestionResultVO;
    }

    private UserQuestionResultVO doJudge(JudgeSubmitDTO judgeSubmitDTO,
                                         UserQuestionResultVO userQuestionResultVO,
                                         SandBoxExecuteResult sandBoxExecuteResult) {
        List<String> exeOutputList = sandBoxExecuteResult.getOutputList();
        List<String> outputList = judgeSubmitDTO.getOutputList();
        if (outputList.size() != exeOutputList.size()) {
            userQuestionResultVO.setScore(JudgeConstants.ERROR_SCORE);
            userQuestionResultVO.setPass(Constants.FALSE);
            userQuestionResultVO.setExeMessage(CodeRunStatus.NOT_ALL_PASSED.getMsg());
            return userQuestionResultVO;
        }
        List<UserExeResult> userExeResultList = new ArrayList<>();
        boolean passed = resultCompare(judgeSubmitDTO, exeOutputList, outputList, userExeResultList);
        return assembleUserQuestionResultVO(judgeSubmitDTO, sandBoxExecuteResult, userQuestionResultVO, userExeResultList, passed);
    }

    private UserQuestionResultVO assembleUserQuestionResultVO(JudgeSubmitDTO judgeSubmitDTO,
                                                              SandBoxExecuteResult sandBoxExecuteResult,
                                                              UserQuestionResultVO userQuestionResultVO,
                                                              List<UserExeResult> userExeResultList, boolean passed) {
        userQuestionResultVO.setUserExeResultList(userExeResultList);
        if (!passed) {
            userQuestionResultVO.setPass(Constants.FALSE);
            userQuestionResultVO.setScore(JudgeConstants.ERROR_SCORE);
            userQuestionResultVO.setExeMessage(CodeRunStatus.NOT_ALL_PASSED.getMsg());
            return userQuestionResultVO;
        }
        if (sandBoxExecuteResult.getUseMemory() > judgeSubmitDTO.getSpaceLimit()) {
            userQuestionResultVO.setPass(Constants.FALSE);
            userQuestionResultVO.setScore(JudgeConstants.ERROR_SCORE);
            userQuestionResultVO.setExeMessage(CodeRunStatus.OUT_OF_MEMORY.getMsg());
            return userQuestionResultVO;
        }
        if (sandBoxExecuteResult.getUseTime() > judgeSubmitDTO.getTimeLimit()) {
            userQuestionResultVO.setPass(Constants.FALSE);
            userQuestionResultVO.setScore(JudgeConstants.ERROR_SCORE);
            userQuestionResultVO.setExeMessage(CodeRunStatus.OUT_OF_TIME.getMsg());
            return userQuestionResultVO;
        }
        userQuestionResultVO.setPass(Constants.TRUE);
        int score = judgeSubmitDTO.getDifficulty() * JudgeConstants.DEFAULT_SCORE;
        userQuestionResultVO.setScore(score);
        return userQuestionResultVO;
    }

    private boolean resultCompare(JudgeSubmitDTO judgeSubmitDTO, List<String> exeOutputList,
                                  List<String> outputList, List<UserExeResult> userExeResultList) {
        boolean passed = true;
        for (int index = 0; index < outputList.size(); index++) {
            String output = outputList.get(index);
            String exeOutPut = exeOutputList.get(index);
            String input = judgeSubmitDTO.getInputList().get(index);
            UserExeResult userExeResult = new UserExeResult();
            userExeResult.setInput(input);
            userExeResult.setOutput(output);
            userExeResult.setExeOutput(exeOutPut);
            userExeResultList.add(userExeResult);
            if (!output.equals(exeOutPut)) {
                passed = false;
                log.info("输入：{}， 期望输出：{}， 实际输出：{} ", input, output, exeOutputList);
            }
        }
        return passed;
    }

    private void saveUserSubmit(JudgeSubmitDTO judgeSubmitDTO, UserQuestionResultVO userQuestionResultVO) {
        UserSubmit userSubmit = new UserSubmit();
        BeanUtil.copyProperties(userQuestionResultVO, userSubmit);
        userSubmit.setUserId(judgeSubmitDTO.getUserId());
        userSubmit.setQuestionId(judgeSubmitDTO.getQuestionId());
        userSubmit.setExamId(judgeSubmitDTO.getExamId());
        userSubmit.setProgramType(judgeSubmitDTO.getProgramType());
        userSubmit.setUserCode(judgeSubmitDTO.getUserCode());
        userSubmit.setCaseJudgeRes(JSON.toJSONString(userQuestionResultVO.getUserExeResultList()));
        userSubmit.setCreateBy(judgeSubmitDTO.getUserId());
        userSubmitMapper.delete(new LambdaQueryWrapper<UserSubmit>()
                .eq(UserSubmit::getUserId, judgeSubmitDTO.getUserId())
                .eq(UserSubmit::getQuestionId, judgeSubmitDTO.getQuestionId())
                .isNull(judgeSubmitDTO.getExamId() == null, UserSubmit::getExamId)
                .eq(judgeSubmitDTO.getExamId() != null, UserSubmit::getExamId, judgeSubmitDTO.getExamId()));
        userSubmitMapper.insert(userSubmit);
    }


//    private UserQuestionResultVO doJudge(JudgeSubmitDTO judgeSubmitDTO, UserQuestionResultVO userQuestionResultVO, SandBoxExecuteResult sandBoxExecuteResult) {
//        //执行成功，对比预期输出与实际输出，时间空间限制
//        List<String> exeOutputList = sandBoxExecuteResult.getOutputList();
//        List<String> outputList = judgeSubmitDTO.getOutputList();
//        List<UserExeResult> userExeResultList = new ArrayList<>();
//        if (assembleJudge(judgeSubmitDTO, userQuestionResultVO, sandBoxExecuteResult, exeOutputList, outputList, userExeResultList))
//            return userQuestionResultVO;
//        userQuestionResultVO.setPass(Constants.TRUE);
//        userQuestionResultVO.setUserExeResultList(userExeResultList);
//        int score = judgeSubmitDTO.getDifficulty() * JudgeConstants.DEFAULT_SCORE;
//        userQuestionResultVO.setScore(score);
//        setResult(Constants.TRUE,userQuestionResultVO,userQuestionResultVO.getExeMessage(),score,userExeResultList);
//        return userQuestionResultVO;
//    }
//
//    private boolean assembleJudge(JudgeSubmitDTO judgeSubmitDTO, UserQuestionResultVO userQuestionResultVO, SandBoxExecuteResult sandBoxExecuteResult, List<String> exeOutputList, List<String> outputList, List<UserExeResult> userExeResultList) {
//        if(exeOutputList.size() != outputList.size()){
//            userQuestionResultVO.setPass(Constants.FALSE);
//            userQuestionResultVO.setExeMessage(CodeRunStatus.NOT_ALL_PASSED.getMsg());
//            userQuestionResultVO.setScore(JudgeConstants.ERROR_SCORE);
//            return true;
//        }
//        for (int i = 0; i < outputList.size(); i++) {
//            UserExeResult userExeResult = new UserExeResult();
//            String intPut = judgeSubmitDTO.getInputList().get(i);
//            String outPut = judgeSubmitDTO.getOutputList().get(i);
//            String exeOutPut = sandBoxExecuteResult.getOutputList().get(i);
//            userExeResult.setInput(intPut);
//            userExeResult.setOutput(outPut);
//            userExeResult.setExeOutput(exeOutPut);
//            userExeResultList.add(userExeResult);
//            if(!outPut.equals(exeOutPut)){
//                //执行结果和预期结果不符
//                setResult(Constants.FALSE, userQuestionResultVO, CodeRunStatus.NOT_ALL_PASSED.getMsg(),JudgeConstants.ERROR_SCORE, userExeResultList);
//                log.info("输入：{}， 期望输出：{}， 实际输出：{} ", intPut, outPut, exeOutputList);
//                return true;
//            }
//        }
//        //比对时间
//        if(sandBoxExecuteResult.getUseTime() >= judgeSubmitDTO.getTimeLimit()){
//            setResult(Constants.FALSE, userQuestionResultVO, CodeRunStatus.OUT_OF_TIME.getMsg(), JudgeConstants.ERROR_SCORE, userExeResultList);
//            return true;
//        }
//        //比对空间
//        if(sandBoxExecuteResult.getUseMemory() >= judgeSubmitDTO.getSpaceLimit()){
//
//            setResult(Constants.FALSE, userQuestionResultVO, CodeRunStatus.OUT_OF_MEMORY.getMsg(), JudgeConstants.ERROR_SCORE, userExeResultList);
//            return true;
//        }
//        return false;
//    }
//
//    private void setResult(Integer pass,UserQuestionResultVO userQuestionResultVO, String message, Integer score,List<UserExeResult> userExeResultList) {
//        userQuestionResultVO.setPass(pass);
//        userQuestionResultVO.setExeMessage(message);
//        userQuestionResultVO.setScore(score);
//        userQuestionResultVO.setUserExeResultList(userExeResultList);
//    }
}
